package com.tj.api.task;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.common.utils.DateUtil;
import com.fqgj.common.utils.StringUtils;
import com.tj.bo.common.conf.config.FileConfigUtil;
import com.tj.bo.common.conf.config.RedisConfigUtil;
import com.tj.bo.common.conf.config.service.BizStatsSqlService;
import com.tj.bo.common.conf.constant.RedisKey;
import com.tj.bo.common.conf.util.DingTalkPushUtils;
import com.tj.bo.common.conf.util.IpUtils;
import com.tj.bo.product.client.ProductService;
import com.tj.bo.product.client.vo.MarketOddsConfig;
import com.tj.bo.product.client.vo.MarketOddsHistory;
import com.tj.bo.product.client.vo.Product;
import com.tj.bo.trade.server.dao.BinaryTradeDao;
import com.tj.bo.trade.server.service.rule.RouterContext;
import com.tj.bo.trade.server.service.rule.RuleResultVO;
import com.tj.bo.trade.server.service.rule.TradeRule;
import com.tj.bo.user.client.UserProductService;
import org.apache.commons.lang.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;

/**
 * @program: binary-option
 * @description 大盘收益率变动任务
 * @author: binary
 * @create: 2020-08-05 17:46
 **/
@Component
public class MarketOddsChangeTask {

    private static final Logger LOGGER = LoggerFactory.getLogger(MarketOddsChangeTask.class);

    @Autowired
    private ProductService productService;
    @Autowired
    private BinaryTradeDao binaryTradeDao;
    @Autowired
    private RedisClient redisClient;
    @Autowired
    private UserProductService userProductService;
    @Autowired
    private RedisConfigUtil redisConfigUtil;
    @Autowired
    private BizStatsSqlService bizStatsSqlService;
    @Autowired
    private FileConfigUtil fileConfigUtil;
    @Autowired
    private Map<String, TradeRule> tradeRuleMap;

    /**
     * 收益率变动
     */
//    @Scheduled(cron = "0 0 0/1 * * ?")
    public void changeMarketOdds() {
        if (!redisConfigUtil.marketOddsTaskOpen()) {
            LOGGER.info("changeMarketOdds,大盘收益率任务开关未打开");
            return;
        }
        String ip = IpUtils.getIp();
        String taskIp = redisConfigUtil.getTaskIp();
        if (!taskIp.equalsIgnoreCase(ip)) {
            LOGGER.info("changeMarketOdds,IP不匹配不执行任务,taskIp:{},localIp:{}", taskIp, ip);
            return;
        }

        LOGGER.info("changeMarketOdds,大盘收益率变动任务START");

        List<MarketOddsConfig> marketOddsConfigInfo = productService.getMarketOddsConfigInfo();
        Date startDate = DateUtil.getPatternDate(new Date(), "yyyy-MM-dd");

        List<Product> products = productService.getAllProductList();
        for (Product product : products) {
            boolean negativePlatformProfit = false;//平台收益为负数 大盘收益改为20%
            boolean moreThanMaxProfit = false;//是否超过最大收益配置上限，超过则还原大盘初始收益率
            BigDecimal marketProfit = null;
            BigDecimal totalAmount = null;
            BigDecimal variableOdds = BigDecimal.ZERO;
            BigDecimal theoreticalOdds = BigDecimal.ZERO;
            Integer totalNum = 0;
            //产品最近一小时订单数少于20 维持原收益率不变
            Integer latestHourTradeNum = binaryTradeDao.countBinaryTradeByTime(product.getProductCode(), DateUtils.addHours(new Date(), -1));
            LOGGER.info("最近一小时【产品Code】:{}，【订单数量】:{}，产品pl触发阈值数量:{}", product.getProductCode(), latestHourTradeNum, redisConfigUtil.getChangeOddsTradeNumbers());
            if(latestHourTradeNum < redisConfigUtil.getChangeOddsTradeNumbers()){
                continue;
            }
            BigDecimal totalPlatformProfit = null;
            BigDecimal maxProfit = new BigDecimal(redisConfigUtil.getMaxPlatformProfitPct());

            Map<String, Object> paramsMap = new HashMap<>();
            paramsMap.put("productCode", product.getProductCode());
            paramsMap.put("startDate", DateUtil.getDate(startDate));
            Object result = bizStatsSqlService.getData("盈利统计", paramsMap);

            LOGGER.info("盈利统计结果,productCode:{},{}", product.getProductCode(), result);

            try {
                JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(result));
                totalNum = jsonObject.getInteger("totalNum");
                totalPlatformProfit = jsonObject.getBigDecimal("totalPlatformProfit");//平台收益率=盈利金额/用户总投入金额
                totalAmount = jsonObject.getBigDecimal("totalAmount");
                marketProfit = jsonObject.getBigDecimal("marketProfit");
                theoreticalOdds = jsonObject.getBigDecimal("odds");//理论pl
            } catch (Exception e) {
                LOGGER.info("changeMarketOdds,盈利统计查询失败,productCode:{}", product.getProductCode());
            }

            if (totalNum >= redisConfigUtil.getChangeOddsTradeNumbers() && totalPlatformProfit != null) {
                for (MarketOddsConfig marketOddsConfig : marketOddsConfigInfo) {
                    if (totalPlatformProfit.compareTo(new BigDecimal(marketOddsConfig.getProfitFloor())) >= 0 && totalPlatformProfit.compareTo(new BigDecimal(marketOddsConfig.getProfitCeil())) < 0) {
                        variableOdds = BigDecimal.valueOf(-1 * Double.parseDouble(marketOddsConfig.getOddsCeil()) / 100).setScale(2, BigDecimal.ROUND_HALF_UP);
                    }
                }

                if (totalPlatformProfit.compareTo(BigDecimal.ZERO) <= 0) {
                    LOGGER.info("changeMarketOdds,收益率降至最低,productCode:{},totalPlatformProfit:{}", product.getProductCode(), totalPlatformProfit);
                    productService.updateProductByMiniOdds(product.getProductCode());
                    negativePlatformProfit = true;
                } else if (totalPlatformProfit.compareTo(maxProfit) > 0) {
                    LOGGER.info("changeMarketOdds,收益率调整为上限值,productCode:{},totalPlatformProfit:{},maxProfit:{}", product.getProductCode(), totalPlatformProfit, maxProfit);
                    productService.updateProductByOdds(product.getProductCode());
                    moreThanMaxProfit = true;
                } else {
                    BigDecimal tmp1 = variableOdds;
                    BigDecimal tmp2 = variableOdds;
                    BigDecimal tmp3 = BigDecimal.valueOf(Double.parseDouble(product.getCurrentOdds()) - Double.parseDouble(product.getOdds())).setScale(2, BigDecimal.ROUND_HALF_UP);
                    if (theoreticalOdds != null) {
                        theoreticalOdds = theoreticalOdds.setScale(2, BigDecimal.ROUND_HALF_UP);
                        if (theoreticalOdds.compareTo(new BigDecimal(product.getOdds())) > 0) {
                            //大于最高值 则取0
                            tmp2 = BigDecimal.ZERO;
                        } else if (theoreticalOdds.compareTo(new BigDecimal(product.getMiniOdds())) < 0) {
                            //小于最低值 则取 最小值-最大值的差值
                            tmp2 = BigDecimal.valueOf(Double.parseDouble(product.getMiniOdds()) - Double.parseDouble(product.getOdds())).setScale(2, BigDecimal.ROUND_HALF_UP);
                        } else {
                            tmp2 = theoreticalOdds.subtract(new BigDecimal(product.getOdds())).setScale(2, BigDecimal.ROUND_HALF_UP);
                        }
                    }
                    List<BigDecimal> list = new ArrayList<>();
                    list.add(tmp1);
                    list.add(tmp2);
                    list.add(tmp3);
                    Collections.sort(list);
                    variableOdds = list.get(0);

                    LOGGER.info("changeMarketOdds,根据限定值调整,productCode:{},totalPlatformProfit:{},tmp1:{},tmp2:{},tmp3:{}", product.getProductCode(), totalPlatformProfit, tmp1, tmp2, tmp3);
                    productService.updateMarketProduct(variableOdds.toPlainString(), product.getProductCode());
                }

                MarketOddsHistory marketOddsHistory = new MarketOddsHistory();
                marketOddsHistory.setProductCode(product.getProductCode());
                marketOddsHistory.setOdds(product.getCurrentOdds());
                productService.insertMarketOddsHistory(marketOddsHistory);

                LOGGER.info("changeMarketOdds,【产品Code】:{} 【平台收益率】: {} 【大盘变动点数】: {}, 【初始化最大收益率】:{},【大盘收益率是否超过初始化最大收益率】: {}, 【大盘收益是否为负】: {},【下单总金额】: {},【平台总收益金额】: {}",
                        product.getProductCode(), totalPlatformProfit, variableOdds, maxProfit, moreThanMaxProfit, negativePlatformProfit, totalAmount, marketProfit);
            }
        }
        redisClient.del(RedisKey.BINARY_OPTION_PRODUCT_CACHE_KEY);
        LOGGER.info("changeMarketOdds,大盘收益率变动任务END");
    }

    /**
     * 收益率监控
     */
//    @Scheduled(cron = "0/5 * * * * ?")
    public void changeUserOdds() {
        Set<String> set = new HashSet<>();
        while (true) {
            String s = (String) redisClient.listRightPop(RedisKey.BINARY_OPTION_ODDS_CALC_LIST);
            if (StringUtils.isEmpty(s)) {
                break;
            }
            set.add(s);
        }
        if (set.isEmpty()) {
            LOGGER.info("changeUserOdds,暂无待处理队列");
            return;
        }

        LOGGER.info("changeUserOdds,待处理用户数:{},{}", set.size(), set.size() <= 100 ? set.toString() : "String too long");

        for (String s : set) {
            try {
                String[] ss = s.split(",");
                String userCode = ss[0];
                String productCode = ss[1];

                RouterContext routerContext = new RouterContext();
                routerContext.setUserCode(userCode);
                routerContext.setProductCode(productCode);
                List<RuleResultVO> ruleResultVOList = new ArrayList<>();
                for (Map.Entry<String, TradeRule> entry : tradeRuleMap.entrySet()) {
                    try {
                        entry.getValue().checkRouterRule(routerContext, ruleResultVOList);
                    } catch (Exception e) {
                        LOGGER.error("规则处理异常,userCode:{}", userCode, e);
                    }
                }
                if (CollectionUtils.isNotEmpty(ruleResultVOList)) {
//                    LOGGER.info("规则集合计算结果排序前,ruleResultVOList:{}", JSON.toJSONString(ruleResultVOList));
                    Collections.sort(ruleResultVOList);
                    LOGGER.info("规则集合计算结果排序后,ruleResultVOList:{}", JSON.toJSONString(ruleResultVOList));

                    userProductService.insertUserProductServiceV2(userCode, productCode, ruleResultVOList.get(0).getChangeValue(), ruleResultVOList.get(0).getRuleName(), ruleResultVOList.get(0).getMessage(), null);
                }
            } catch (Exception e) {
                LOGGER.error("计算收益率错误,s:{}", s, e);
            }
        }
        LOGGER.info("changeUserOdds,处理完成:{}", set.size());
    }

    /**
     * 收益率监控
     */
//    @Scheduled(cron = "0 0/15 * * * ?")
    public void marketOddsMonitor() {
        List<Product> products = productService.getAllProductList();
        for (Product product : products) {

            Map<String, Object> paramsMap = new HashMap<>();
            paramsMap.put("productCode", product.getProductCode());

            try {
                Object result = bizStatsSqlService.getData("Win rate statistics", paramsMap);
                JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(result));
                Integer totalNum = jsonObject.getInteger("totalNum");
                Integer winNum = jsonObject.getInteger("winNum");
                BigDecimal winRate = jsonObject.getBigDecimal("winRate");
                BigDecimal investInAmt = jsonObject.getBigDecimal("investInAmt");
                BigDecimal outputAmount = jsonObject.getBigDecimal("outputAmount");
                BigDecimal income = jsonObject.getBigDecimal("income");

                LOGGER.info("当前胜率,{},{}", product.getProductCode(), jsonObject.toJSONString());

                if (winRate != null && totalNum >= 20 && winRate.doubleValue() >= 0.83) {
                    if (!fileConfigUtil.isServerTest()) {
                        DingTalkPushUtils.pushTextMessageAtAll("[提醒]用户SL超过83%,执行下架操作," + product.getProductCode());
                    }

                    String productCode = product.getProductCode();
                    Product product2 = new Product();
                    product2.setProductCode(productCode);
                    product2.setLocked(true);
                    productService.updateProductBasicInfoByProductCode(productCode, product2);

                    LOGGER.warn("用户SL超过83%,执行下架操作," + product.getProductCode());
                }
            } catch (Exception e) {
                LOGGER.error("统计异常,productCode:{}", product.getProductCode(), e);
            }
        }

    }

}
